import React from "react";
import PropTypes from "prop-types";
import moment from "moment";
import ControlledProps from "@cbd/controlled-props/es/ControlledProps";
import { Calendar } from "antd";
import cn from "classnames";
import styles from "./WeekCalendar.less";

const hasClass = (classList, className) => {
  for (let i = 0; i < classList.length; i += 1) {
    const cls = classList[i];
    if (cls === className) {
      return true;
    }
  }
  return false;
};

const getTargetDateTitle = (e) => {
  if (e && e.target) {
    let { target } = e;
    while (target !== document.body) {
      if (hasClass(target.classList, "ant-fullcalendar-date")) {
        return target.getAttribute("date");
      }
      target = target.parentNode;
    }
  }
  return undefined;
};

@ControlledProps({
  range: undefined,
})
class WeekCalendar extends React.Component {

  mousedown = false;

  startDate = "";

  endDate = "";

  mousemove = false;

  constructor(props) {
    super(props);
    moment.locale("zh-cn", {
      weekdaysMin: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
      week: { dow: 0 },
    });
  }

  addMouseUpListener = () => {
    window.addEventListener("mouseup", this.handleWindowMouseUp);
  };

  removeMouseUpListener = () => {
    window.removeEventListener("mouseup", this.handleWindowMouseUp);
  };

  handleWindowMouseUp = () => {
    const { onRangeChangeComplete } = this.props;
    const { range } = this.state;

    if (this.mousedown) {
      this.mousedown = false;
      this.removeMouseUpListener();
    }
    if (this.mousemove) {
      this.mousemove = false;
      onRangeChangeComplete(range);
    }
  };

  handleMouseDown = (e) => {
    const { rangeMode } = this.props;
    if (rangeMode) {
      const date = getTargetDateTitle(e);
      if (!date) {
        return;
      }
      this.startDate = date;
      this.endDate = date;
      this.mousedown = true;
      this.triggerRangeChange();
      this.addMouseUpListener();
      e.preventDefault();
    }
  };


  handleMouseMove = (e) => {
    if (this.mousedown) {
      const date = getTargetDateTitle(e);
      if (!date) {
        return;
      }
      if (date !== this.endDate) {
        this.mousemove = true;
        this.endDate = date;
        this.triggerRangeChange();
      }
    }
  };

  triggerRangeChange = () => {
    const { startDate, endDate } = this;
    const s = moment(startDate);
    const e = moment(endDate);
    if (s.unix() > e.unix()) {
      this.changeProps({ range: [e, s] });
    } else {
      this.changeProps({ range: [s, e] });
    }
  };

  dateCellRender = (date, ...other) => {
    const { dateCellRender = () => null } = this.props;
    const { range } = this.state;

    let inRange = false;
    if (range) {
      const [startMoment, endMoment] = range;
      const dateStr = date.format("YYYYMMDD");
      const startStr = startMoment.format("YYYYMMDD");
      const endStr = endMoment.format("YYYYMMDD");
      if (dateStr >= startStr && dateStr <= endStr) {
        inRange = true;
      }
    }
    return (
      <div
        className={cn("ant-fullcalendar-date", { [styles.inRange]: inRange })}
        date={date.format("YYYY-MM-DD")}
      >
        <div className="ant-fullcalendar-value">{date.date()}</div>
        <div className="ant-fullcalendar-content">
          {
            dateCellRender(date, range, inRange, ...other)
          }
        </div>
      </div>
    );
  };

  render() {
    const { range, ...otherProps } = this.props;
    return (
      <div
        className={styles.root}
        onMouseMove={this.handleMouseMove}
        onMouseDown={this.handleMouseDown}
      >
        <Calendar
          locale={{ locale: "zh-cn" }}
          {...otherProps}
          dateFullCellRender={this.dateCellRender}
        />
      </div>
    );
  }
}

WeekCalendar.propTypes = {
  range: PropTypes.arrayOf(PropTypes.object),
  rangeMode: PropTypes.bool,
  onRangeChangeComplete: PropTypes.func,
};

WeekCalendar.defaultProps = {
  range: undefined,
  rangeMode: false,
  onRangeChangeComplete: () => {

  },
};


export default WeekCalendar;
